package com.fneuch.mwg.w40k.rule;

import org.springframework.stereotype.Component;

import com.fneuch.mwg.army.Unit;
import com.fneuch.mwg.profiles.DefenseProfile;
import com.fneuch.mwg.profiles.ModelProfile;
import com.fneuch.mwg.profiles.ShootingProfile;
import com.fneuch.mwg.rules.AttackResult;
import com.fneuch.mwg.rules.ShootingRuleEngine;
import com.fneuch.mwg.rules.shooting.ShootingResult;

@Component
public class ShootingEngine extends AbstractRuleEngine implements ShootingRuleEngine {
	@Override
	public AttackResult execute(Unit attacker, Unit defender) {
		ShootingResult result = attacker.getModels().isEmpty() ? null:new ShootingResult();
		int nbTotalDefenders = defender.getNbModels();
		int nbTotalAttacker = attacker.getNbModels();
		
		DefenseProfile averageDefenseProfile = (DefenseProfile) defender.getLargestNumberModel(defender);
		
		// The attacking side action 
		for(ModelProfile model:attacker.getModels().keySet()) {
			ShootingProfile shooter = (ShootingProfile)model;
			// Counting nb Shoot
			double nbShooter = attacker.getModels().get(model).intValue();
			result.setNbAttacks(result.getNbAttacks() + (int)nbShooter);
			// Counting hit hit
			double toHitPercent = toHit(shooter.getBallisticSkill()) ;
			result.setToHit(result.getToHit() + (int)(toHitPercent * (nbShooter / nbTotalAttacker)));
			if(result.getToHit() > 100) {
				result.setToHit(100);
			}
			// Counting total wound
			double toWoundPercent = toWound(shooter.getStrength(), averageDefenseProfile.getToughness()); 
			result.setToWound(result.getToWound() +  (int)(toWoundPercent * (nbShooter / nbTotalAttacker)));
			if(result.getToWound() > 100) {
				result.setToWound(100);
			}			
					}
		result.setNbHits((int)Math.round(result.getNbAttacks() * result.getToHit()/100));
		result.setNbWounded((int)Math.round(result.getNbHits() * result.getToWound()/100));
		
		// we must find an average save percentage
		for(ModelProfile model:defender.getModels().keySet()) {
			DefenseProfile defenderModel = (DefenseProfile)model;
			double nbDefender = defender.getModels().get(model).intValue();
			double toSavePercent = toSave(defenderModel.getSave()); 
			result.setToSave(result.getToSave() + (int)(toSavePercent   * (nbDefender / nbTotalDefenders)));
		}
		// Calculating defense result
		result.setNbSaved((int)Math.round(result.getNbWounded() * result.getToSave()/100));
		int damaged = result.getNbWounded()- result.getNbSaved();
		result.setNbDefenderLeft(nbTotalDefenders - damaged);

		return result;
	}
	
	public int toHit(int statsValue) {
		int result = 0;
		
		if(statsValue < 6) {
			result = probability.over(7-statsValue);
		}else{
			int underResult = probability.over(2);
			int overMaxValue = statsValue -6;
			int rerollResult = probability.over(6-overMaxValue);
			result = underResult + (100-underResult)*rerollResult/100;
		}
		
		return result;
	}

	@Override
	public AttackResult shoot(int nbShooter, ShootingProfile shooter, int nbDefenders, DefenseProfile defender) {
		ShootingResult result = new ShootingResult();
		
		result.setNbAttacks(nbShooter);
		double toHitPercent = toHit(shooter.getBallisticSkill());
		result.setToHit((int)toHitPercent);
		result.setNbHits((int)Math.round(nbShooter * toHitPercent/100));
		double toWoundPercent = toWound(shooter.getStrength(), defender.getToughness()); 
		result.setToWound((int)toWoundPercent);
		result.setNbWounded((int)Math.round(result.getNbHits() * toWoundPercent/100));
		double toSavePercent = toSave(defender.getSave()); 
		result.setToSave((int)toSavePercent);
		result.setNbSaved((int)Math.round(result.getNbWounded() * toSavePercent/100));
		int damaged = result.getNbWounded()- result.getNbSaved();
		result.setNbDefenderLeft(nbDefenders - damaged);
		return result;
	}
}
